package com.gzx.bi.modular.screen.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.gzx.bi.modular.screen.constant.StatisticBIConstant;
import com.gzx.bi.modular.screen.entity.GzxStatisticBI;
import com.gzx.bi.modular.screen.mapper.GzxStatisticBIMapper;
import com.gzx.bi.modular.screen.service.GzxHtCallRecordService;
import com.gzx.bi.modular.screen.service.GzxStatisticBIService;
import com.gzx.bi.modular.screen.util.ScreenDateUtils;
import com.gzx.bi.modular.screen.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * bi报表服务实现类
 *
 * @author xbl
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GzxStatisticBIServiceImpl implements GzxStatisticBIService {

    //bi报表mapper
    private final GzxStatisticBIMapper baseMapper;

    //话单service
    private final GzxHtCallRecordService htCallRecordService;

    //插入数据，存在则更新，不存在则插入
    @DS("bi")
    @Override
    public void insertOnDuplicate(String type, String jsonStr, String currentDate) {
        //封装bi数据
        GzxStatisticBI bi = new GzxStatisticBI();
        bi.setBiType(type);
        bi.setBiMonth(currentDate);
        bi.setBiResult(jsonStr);
        //定时任务获取不到登录信息
        bi.setTenantId(StatisticBIConstant.SYSTEM_TENANT_ID);
        baseMapper.insertOnDuplicate(bi);
    }

    //获取待合并的数据
    @DS("bi")
    @Override
    public List<GzxStatisticBI> getMergeData(String currentMonth, String biType) {
        return baseMapper.getMergeData(currentMonth, biType);
    }

    //根据报表类型获取报表结果
    @DS("bi")
    @Override
    public GzxStatisticBIVo getResultByType(String type) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();
        //查询每月最新版本的数据(一种报表一天只有一条)
        List<GzxStatisticBI> list = getMergeData(DateUtil.format(new Date(), "yyyy-MM"), type);
        //根据不同的类型查询报表
        switch (type) {
            case StatisticBIConstant.MONTH_CALL_STATISTICS_DAY:
                //本月通话统计
                vo = mergeMonthCall(list);
                break;
            case StatisticBIConstant.TEAM_AGENT_STATISTICS_DAY:
                //团队坐席统计
                vo = mergeTeamAgent(list);
                break;
            case StatisticBIConstant.CALL_TREND_ANALYSIS_DAY:
                //通话趋势分析
                vo = mergeCallTrend(list);
                break;
            case StatisticBIConstant.AGENT_STATUS_STATISTICS_DAY:
                //坐席状态统计
                vo = mergeAgentStatus(list);
                break;
            case StatisticBIConstant.TODAY_CALL_ANALYSIS_DAY:
                //今日通话分析
                vo = mergeTodayCall(list);
                break;
            case StatisticBIConstant.HISTORY_ANSWER_RATE_ANALYSIS_DAY:
                //历史接通分析
                vo = mergeHistoryAnswer(list);
                break;
            case StatisticBIConstant.MAIN_STATISTICS_DAY:
                //主报表
                vo = mergeMain(list);
                break;
            default:
                break;
        }
        return vo;
    }

    //合并主报表
    private GzxStatisticBIVo mergeMain(List<GzxStatisticBI> list) {
        return htCallRecordService.mergeMain(list);
    }

    //历史接通分析
    private GzxStatisticBIVo mergeHistoryAnswer(List<GzxStatisticBI> list) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();
        GzxHistoryAnswerVo historyAnswerVo = new GzxHistoryAnswerVo();
        //历史接通分析 - 活跃线路呼出总数统计
        List<GzxActiveLineVo> activeLineVos = new ArrayList<>();
        //当天呼叫统计
        List<GzxCallStatisticVo> callStatistic = new ArrayList<>();
        //客户分布统计
        List<GzxCustomerDistributionVo> customerDistribution = new ArrayList<>();
        for (GzxStatisticBI bi : list) {
            JSONObject json = JSON.parseObject(bi.getBiResult());
            List<GzxActiveLineVo> alv = JSON.parseArray(json.getString("activeLineCall"), GzxActiveLineVo.class);
            activeLineVos.addAll(alv);
            GzxCallStatisticVo asv = JSON.parseObject(json.getString("callStatisticVo"), GzxCallStatisticVo.class);
            callStatistic.add(asv);
            List<GzxCustomerDistributionVo> cdv = JSON.parseArray(json.getString("customerDistribution"), GzxCustomerDistributionVo.class);
            customerDistribution.addAll(cdv);
        }
        //活跃线路呼出总数 - 根据线路和地区分组，sum总数和呼出总数
        List<GzxActiveLineVo> activeLineResult = activeLineVos.stream()
                .collect(Collectors.groupingBy(
                        GzxActiveLineVo::getLineName,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                lineVos -> {
                                    double totalSum = lineVos.stream().mapToDouble(GzxActiveLineVo::getCallTotal).sum();
                                    double callCompletionSum = lineVos.stream().mapToDouble(GzxActiveLineVo::getCallCompletionTotal).sum();
                                    return new GzxActiveLineVo(lineVos.getFirst().getLineName(), totalSum, callCompletionSum);
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //活跃线路呼出总数 - 计算接通率
        for (GzxActiveLineVo activeLineVo : activeLineResult) {
            activeLineVo.setCallCompletionRate(Double.valueOf(String.format("%.2f", (double) activeLineVo.getCallCompletionTotal() / activeLineVo.getCallTotal())));
        }
        //线路排行榜按照接通率倒叙
        activeLineResult = activeLineResult.stream().sorted(Comparator.comparing(GzxActiveLineVo::getCallCompletionRate).reversed()).toList();
        //活跃线路呼出总数
        historyAnswerVo.setActiveLineCall(activeLineResult);

        //呼叫统计 - 计算接通率
        for (GzxCallStatisticVo callStatisticVo : callStatistic) {
            callStatisticVo.setCallCompletionRate(Double.valueOf(String.format("%.2f", (double) callStatisticVo.getCallCompletionTotal() / callStatisticVo.getCallTotal())));
        }
        historyAnswerVo.setCallStatistic(callStatistic);

        //客户分布统计 - 按照地区分组，sum总数和呼出总数
        List<GzxCustomerDistributionVo> customerDistributionResult = customerDistribution.stream()
                .collect(Collectors.groupingBy(
                        GzxCustomerDistributionVo::getAreaName,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                group -> {
                                    GzxCustomerDistributionVo r = new GzxCustomerDistributionVo();
                                    r.setAreaName(group.getFirst().getAreaName());
                                    r.setCallTotal(group.stream().mapToInt(GzxCustomerDistributionVo::getCallTotal).sum());
                                    r.setCallCompletionTotal(group.stream().mapToInt(GzxCustomerDistributionVo::getCallCompletionTotal).sum());
                                    return r;
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //计算客户分布统计接通率
        for (GzxCustomerDistributionVo customerDistributionVo : customerDistributionResult) {
            customerDistributionVo.setCallCompletionRate(Double.valueOf(String.format("%.2f", (double) customerDistributionVo.getCallCompletionTotal() / customerDistributionVo.getCallTotal())));
        }
        historyAnswerVo.setCustomerDistribution(customerDistributionResult);

        vo.setBiResult(JSON.toJSONString(historyAnswerVo));
        log.info("历史接通分析 合并之后的结果 -> {} ", vo);
        return vo;
    }

    //合并今日通话分析
    private GzxStatisticBIVo mergeTodayCall(List<GzxStatisticBI> list) {
        return htCallRecordService.mergeTodayCall(list);
    }

    //合并坐席状态统计
    private GzxStatisticBIVo mergeAgentStatus(List<GzxStatisticBI> list) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();
        //坐席状态统计
        GzxAgentStatusVo agentStatusVo = new GzxAgentStatusVo();
        //所有的职场
        List<GzxOfficeCallVo> officeCallVos = new ArrayList<>();
        //top10坐席的通话量
        List<GzxAgentCallVo> agentCallVos = new ArrayList<>();
        for (GzxStatisticBI bi : list) {
            GzxAgentStatusVo biVo = JSON.parseObject(bi.getBiResult(), GzxAgentStatusVo.class);
            //所有职场（调解中心）通话量
            officeCallVos.add(biVo.getOfficeCallVo());

            //top10坐席的通话量
            agentCallVos.addAll(biVo.getAgentCallVos());
        }
        agentStatusVo.setOfficeVos(officeCallVos);

        //top10职场的通话量，按照坐席通话时长排序，取前10个
        List<GzxAgentCallVo> agentResult = agentCallVos.stream()
                // 按数值降序排序
                .sorted(Comparator.comparing(GzxAgentCallVo::getCallDuration).reversed())
                // 取前10个
                .limit(10)
                .toList();
        agentStatusVo.setAgentCallVos(agentResult);

        vo.setBiResult(JSON.toJSONString(agentStatusVo));
        log.info("坐席状态分析 合并之后的结果 -> {} ", vo);
        return vo;
    }

    //合并通话趋势分析
    private GzxStatisticBIVo mergeCallTrend(List<GzxStatisticBI> list) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();

        //呼叫类型分布和结果分布
        List<GzxCommonVo> callTypes = new ArrayList<>(), callResults = new ArrayList<>();
        List<GzxCallSummaryVo> callSummaryStatistics = new ArrayList<>();
        GzxCallTrendVo trendVo = new GzxCallTrendVo();
        for (GzxStatisticBI bi : list) {
            JSONObject json = JSON.parseObject(bi.getBiResult());
            List<GzxCommonVo> callType = JSON.parseArray(json.getString("callTypeDistribution"), GzxCommonVo.class);
            callTypes.addAll(callType);
            List<GzxCommonVo> callResult = JSON.parseArray(json.getString("callResultDistribution"), GzxCommonVo.class);
            callResults.addAll(callResult);
            //通话总量统计
            GzxCallSummaryVo summary = JSON.parseObject(json.getString("callSummary"), GzxCallSummaryVo.class);
            callSummaryStatistics.add(summary);
        }
        trendVo.setCallSummaryStatistics(callSummaryStatistics);

        //呼叫类型分布按照name分组并sum(value)
        List<GzxCommonVo> callTypeSum = callTypes.stream()
                .collect(Collectors.groupingBy(
                        GzxCommonVo::getName,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                group -> {
                                    GzxCommonVo r = new GzxCommonVo();
                                    r.setName(group.getFirst().getName());
                                    r.setValue(group.stream().mapToInt(GzxCommonVo::getValue).sum());
                                    return r;
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //呼叫结果分布按照name分组并sum(value)
        List<GzxCommonVo> callResultSum = callResults.stream()
                .collect(Collectors.groupingBy(
                        GzxCommonVo::getName,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                group -> {
                                    GzxCommonVo r = new GzxCommonVo();
                                    r.setName(group.getFirst().getName());
                                    r.setValue(group.stream().mapToInt(GzxCommonVo::getValue).sum());
                                    return r;
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //通话趋势分析 - 呼叫类型分布 0：呼入；1：呼出；2：多人外呼 总条数
        int callTypeTotal = callTypeSum.stream().mapToInt(GzxCommonVo::getValue).sum();
        for (GzxCommonVo commonVo : callTypeSum) {
            commonVo.setRate(Double.parseDouble(String.format("%.2f", (double) commonVo.getValue() / callTypeTotal)));
            switch (commonVo.getName()) {
                case "0":
                    commonVo.setName("呼入");
                    break;
                case "1":
                    commonVo.setName("呼出");
                    break;
                case "2":
                    commonVo.setName("预测外呼");
                    break;
                default:
                    break;
            }
        }

        //通话趋势分析 - 呼叫类型分布 总条数
        int callResultTotal = callResultSum.stream().mapToInt(GzxCommonVo::getValue).sum();
        for (GzxCommonVo commonVo : callResultSum) {
            commonVo.setRate(Double.parseDouble(String.format("%.2f", (double) commonVo.getValue() / callResultTotal)));
        }

        trendVo.setCallTypeDistribution(callTypeSum);
        trendVo.setCallResultDistribution(callResultSum);
        vo.setBiResult(JSON.toJSONString(trendVo));
        log.info("通话趋势分析 合并之后的结果 -> {} ", vo);
        return vo;
    }

    //合并团队坐席统计
    private GzxStatisticBIVo mergeTeamAgent(List<GzxStatisticBI> list) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();
        List<GzxCallTotalVo> callTotalList = new ArrayList<>();
        List<GzxCallOutgoingVo> callOutgoingList = new ArrayList<>();
        for (GzxStatisticBI bi : list) {
            GzxTeamAgentVo team = JSON.parseObject(bi.getBiResult(), GzxTeamAgentVo.class);
            callTotalList.addAll(team.getCallTotalList());
            callOutgoingList.addAll(team.getCallOutgoingList());
        }
        //封装bi_result
        JSONObject json = new JSONObject();
        //计算每个职场的通话总数，通话接通总数，通话接通率，通话接通总时长（分钟），通话响铃总时长（分钟）
        //按照职场deptId分组,把其他属性sum一起
        List<GzxCallTotalVo> callResults = callTotalList.stream()
                .collect(Collectors.groupingBy(
                        GzxCallTotalVo::getDeptId,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                group -> {
                                    GzxCallTotalVo r = new GzxCallTotalVo();
                                    r.setDeptId(group.getFirst().getDeptId());
                                    r.setDeptName(group.getFirst().getDeptName());
                                    r.setCallTotal(group.stream().mapToInt(GzxCallTotalVo::getCallTotal).sum());
                                    r.setCallCompletionTotal(group.stream().mapToInt(GzxCallTotalVo::getCallCompletionTotal).sum());
                                    r.setTotalCallDuration(group.stream().mapToDouble(GzxCallTotalVo::getTotalCallDuration).sum());
                                    r.setRingDuration(group.stream().mapToDouble(GzxCallTotalVo::getRingDuration).sum());
                                    return r;
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //计算接通率
        for (GzxCallTotalVo r : callResults) {
            r.setCallCompletionRate(Double.valueOf(String.format("%.2f", (double) r.getCallCompletionTotal() / r.getCallTotal())));
        }

        //计算每个职场的呼叫总数，呼叫接通总数，呼叫接通率，接通总时长（分钟），响铃总时长（分钟）
        List<GzxCallOutgoingVo> callOutResults = callOutgoingList.stream()
                .collect(Collectors.groupingBy(
                        GzxCallOutgoingVo::getDeptId,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                group -> {
                                    GzxCallOutgoingVo r = new GzxCallOutgoingVo();
                                    r.setDeptId(group.getFirst().getDeptId());
                                    r.setDeptName(group.getFirst().getDeptName());
                                    r.setCallOutgoingTotal(group.stream().mapToInt(GzxCallOutgoingVo::getCallOutgoingTotal).sum());
                                    r.setCallOutgoingCompletionTotal(group.stream().mapToInt(GzxCallOutgoingVo::getCallOutgoingCompletionTotal).sum());
                                    r.setTotalCallOutgoingDuration(group.stream().mapToDouble(GzxCallOutgoingVo::getTotalCallOutgoingDuration).sum());
                                    r.setCallOutgoingRingDuration(group.stream().mapToDouble(GzxCallOutgoingVo::getCallOutgoingRingDuration).sum());
                                    return r;
                                }
                        )
                ))
                .values()
                .stream()
                .toList();

        //计算接通率
        for (GzxCallOutgoingVo r : callOutResults) {
            r.setCallOutgoingCompletionRate(Double.valueOf(String.format("%.2f", (double) r.getCallOutgoingCompletionTotal() / r.getCallOutgoingTotal())));
        }
        json.put("callTotalList", callResults);
        json.put("callOutgoingList", callOutResults);
        vo.setBiResult(json.toJSONString());
        log.info("合并后的合并团队坐席统计数据 -> {} ", vo);
        return vo;
    }

    //合并当月数据
    private GzxStatisticBIVo mergeMonthCall(List<GzxStatisticBI> list) {
        GzxStatisticBIVo vo = new GzxStatisticBIVo();
        List<GzxMonthCallVo> listMonth = new ArrayList<>();
        //定时任务已经跑完当月所有数据，这里查到的是当月此种报表的所有数据，拼接成一个对象返回给前端即可
        for (GzxStatisticBI bi : list) {
            GzxMonthCallVo dayCall = JSON.parseObject(bi.getBiResult(), GzxMonthCallVo.class);
            listMonth.add(dayCall);
        }
        //封装bi_result
        JSONObject json = new JSONObject();
        //计算接通率，出勤坐席数量等
        int callTotal = listMonth.stream().mapToInt(GzxMonthCallVo::getCallTotal).sum();
        json.put("callTotal", callTotal);
        long callCompletionTotal = listMonth.stream().mapToLong(GzxMonthCallVo::getCallCompletionTotal).sum();
        json.put("callCompletionTotal", callCompletionTotal);
        json.put("callCompletionRate", Double.valueOf(String.format("%.2f", callCompletionTotal / (double) callTotal)));
        long activeSeatsNum = listMonth.stream().mapToLong(GzxMonthCallVo::getActiveSeatsNum).sum();
        json.put("activeSeatsNum", activeSeatsNum);
        //通话总时长（分钟
        double totalCallDuration = listMonth.stream().mapToDouble(GzxMonthCallVo::getTotalCallDuration).sum();
        json.put("totalCallDuration", Double.valueOf(String.format("%.2f", totalCallDuration)));
        double totalIncomingCall = listMonth.stream().mapToDouble(GzxMonthCallVo::getTotalIncomingCall).sum();
        json.put("totalIncomingCall", Double.valueOf(String.format("%.2f", totalIncomingCall)));
        double callDurationOutgoing = listMonth.stream().mapToDouble(GzxMonthCallVo::getCallDurationOutgoing).sum();
        json.put("callDurationOutgoing", Double.valueOf(String.format("%.2f", callDurationOutgoing)));
        //呼入接通率
        double incomingCallRate = Double.parseDouble(String.format("%.2f", callDurationOutgoing / totalIncomingCall));
        json.put("incomingCallRate", incomingCallRate);
        //坐席每日出席天数
        json.put("activeSeats", JSON.toJSONString(listMonth));
        vo.setBiResult(json.toJSONString());
        log.info("合并后的当月数据 -> {} ", vo);
        return vo;
    }

    // 填充空余时间段的数据
    private List<Map<String, String>> fillMissingDates(List<Map<String, String>> list, String month) {
        List<Map<String, String>> dateList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, Integer.parseInt(month.split("-")[0]));
        calendar.set(Calendar.MONTH, Integer.parseInt(month.split("-")[1]) - 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 获取当前日期
        Date currentDate = new Date();
        for (int day = 1; day <= daysInMonth; day++) {
            //只获取从月初到当天日期
            if (calendar.getTime().before(currentDate) || calendar.getTime().equals(currentDate)) {
                calendar.set(Calendar.DAY_OF_MONTH, day);
                String date = ScreenDateUtils.getMonthDay();
                Map<String, String> newDateMap = new HashMap<>(); // 创建一个新的 Map 对象
                newDateMap.put(StatisticBIConstant.DATE_KEY, date);
                newDateMap.put(StatisticBIConstant.SEATS_KEY, "0");
                for (Map<String, String> entry : list) {
                    String entryDate = ObjectUtils.isNull(entry.get(StatisticBIConstant.DATE_KEY)) ? "" : entry.get(StatisticBIConstant.DATE_KEY).trim();
                    if (date.equals(entryDate)) {
                        newDateMap.put(StatisticBIConstant.SEATS_KEY, String.valueOf(entry.getOrDefault(StatisticBIConstant.SEATS_KEY, "0")));
                    }
                }
                dateList.add(newDateMap); // 添加新的 Map 对象到 dateList
                log.info("calendar -> {} ", calendar.getTime());
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
        }
        return dateList;
    }
}
